<script lang="ts" setup>
import {SizeUtil} from '@xtail/ui'
import {VueDraggable} from 'vue-draggable-plus'
import {SIcon} from '@xtail/vue3'
import Settings from '@iconify-icons/tabler/settings'
import ArrowsMoveVertical from '@iconify-icons/tabler/arrows-move-vertical'
import {XCollapseBtn} from '../XCollapseBtn'
import {XQuestionTip} from '../XQuestionTip'
import type {CrudColSettingPropsType, CrudColumns, CrudColumn} from './types'

defineOptions({
  name: 'XCrudColSetting',
})

const props = withDefaults(defineProps<CrudColSettingPropsType>(), {
  useBuiltInSelectColumn: true,
  triggerBtnText: '列设置',
  triggerBtnCollapse: false,
  triggerBtnProps: {} as any,
  colSettingPopoverMaxWidth: '200px',
  colSettingListMaxHeight: '300px',
  colSettingPopoverProps: {} as any,
  colShowTabName: '列展示',
  colFixTabName: '列固定',
  colAlignTabName: '列对齐',
  allBtnText: '全选',
  colShowAllTipProps: {} as any,
  colFixAllTipProps: {} as any,
  resetBtnText: '重置',
  leftBtnText: '左',
  centerBtnText: '居中',
  rightBtnText: '右',
  colSettingListScrollbarProps: {} as any,
})

const columns = defineModel<CrudColumns>('columns', {default: []})

const slots = useSlots()

defineExpose({
  getColumnsBackup: () => columnsBackup.value
})

// 表格列配置的浅备份，用于列配置重置、列配置弹框显示
const columnsBackup = ref<CrudColumns>([])

// 表格勾选列的配置
const selectableColumn: CrudColumn = {
  type: 'selection',
  className: '',
  title: '勾选列',
  disableChecked: true,
  checked: true,
  draggable: false,
  fixed: 'left',
}
/**
 * 预处理表格列配置
 */
onBeforeMount(() => {
  columnsBackup.value = [...columns.value]
  // 使用内置的选择列的配置
  if (props.useBuiltInSelectColumn) {
    columnsBackup.value = [selectableColumn, ...columnsBackup.value]
  }
  // 表格列配置初始值预处理与备份并设置表格列排序
  let idx = 0
  for (const column of columnsBackup.value) {
    // 如果原来的列配置中具有 checked 属性，且值为 false，则该列的 checked 属性设置为 false，否则设置为 true
    column.checked = !(Reflect.has(column, 'checked') && column.checked === false)
    // 表格列初始状态下，是否选中展示
    column.originChecked = column.checked
    // 如果原来的列配置中具有 draggable 属性，且值为 false，则该列的 draggable 属性设置为 false，否则设置为 true
    column.draggable = !(Reflect.has(column, 'draggable') && column.draggable === false)
    // 如果原来的列配置中不具有 align 属性，则该列的 align 属性设置为 'center'
    column.align = Reflect.has(column, 'align') ? column.align : 'center'
    // 表格列初始状态下，对其方式
    column.originAlign = column.align
    // 表格列初始状态下，是否固定
    column.originFixed = column.fixed
    // 设置表格列的排序
    column.sort = idx++
  }
  // 备份初始状态下的表格列
  columns.value = columnsBackup.value
})

// 需要展示的表格列是否为部分表格列
const isColumnsShowedIndeterminate = ref(false)
// 需要展示的表格列是否为全部表格列
const isColumnsShowedAll = ref(false)
// 是否只有部分列固定
const isColumnsFixedIndeterminate = ref(false)
// 是否所有列都固定
const isColumnsFixedAll = ref(false)
/**
 * 表格列发生更新的处理函数
 */
const columnsUpdateHandler = () => {
  // 可以选择是否选中展示的列的总个数
  let columnsShowedSum = 0
  // 记录需要展示的表格列的个数
  let columnsShowedCount = 0
  // 可以选择是否固定的列的总个数
  let columnsFixedSum = 0
  // 固定列的个数
  let columnsFixedCnt = 0
  // 更新需要展示的表格列
  columns.value = columnsBackup.value.filter(column => {
    if (!column.disableChecked) columnsShowedSum++
    if (!column.disableChecked && column.checked) columnsShowedCount++
    if (column.originFixed) columnsFixedSum++
    if (column.fixed) columnsFixedCnt++
    return column.checked
  })
  const columnsBackupLen = columnsBackup.value.length
  // 判断需要展示的表格列是否为部分表格列
  isColumnsShowedIndeterminate.value = columnsBackupLen > 0 && columnsShowedCount > 0 && columnsShowedCount < columnsShowedSum
  // 判断需要展示的表格列是否为全部表格列
  isColumnsShowedAll.value = columnsBackupLen > 0 && columnsShowedCount === columnsShowedSum
  // 判断是否只有部分列固定
  isColumnsFixedIndeterminate.value = columnsBackupLen > 0 && columnsFixedCnt > 0 && columnsFixedCnt < columnsFixedSum
  // 判断是否所有表格列都固定
  isColumnsFixedAll.value = columnsBackupLen > 0 && columnsFixedCnt === columnsFixedSum
}
// 监听 columns 变化
watchEffect(() => {
  columnsUpdateHandler()
})

/**
 * 更新表格列展示的全选复选框是否选中的处理函数
 *
 * @param checked 表格列展示的全选复选框是否选中
 */
const updateColumnsShowedAllHandler = (checked: boolean) => {
  for (const column of columnsBackup.value) {
    if (!column.disableChecked) {
      column.checked = checked
    }
  }
}

/**
 * 重置表格列的展示状态
 */
const resetColumnsShowedHandler = () => {
  for (const column of columnsBackup.value) {
    column.checked = column.originChecked
  }
  columns.value = columnsBackup.value.sort((a, b) => (a.sort as number) - (b.sort as number))
}

/**
 * 更新表格列固定的全选复选框是否选中的处理函数
 *
 * @param {boolean} checked 表格列固定的全选复选框是否选中
 */
const updateColumnsFixedAllHandler = (checked: boolean) => {
  for (const column of columnsBackup.value) {
    // 只有设置了 fixed 属性的列才能被全选按钮改变固定状态
    if (column.originFixed) {
      column.fixed = (checked ? column.originFixed : false) as 'left' | 'right' | undefined
    }
  }
}

/**
 * 重置表格列的固定
 */
const resetColumnsFixedHandler = () => {
  for (const column of columnsBackup.value) {
    column.fixed = column.originFixed
  }
}

/**
 * 重置表格列的内容对其方式
 */
const resetColumnsAlignHandler = () => {
  for (const column of columnsBackup.value) {
    column.align = column.originAlign
  }
}
</script>

<template>
  <div class="x-crud-col-setting">
    <n-popover
      v-bind="{
        style: {
          maxWidth: SizeUtil.unitPreHandler(colSettingPopoverMaxWidth),
        },
        to: false,
        ...colSettingPopoverProps,
      }"
    >
      <template #trigger>
        <slot name="trigger">
          <x-collapse-btn
            :text="triggerBtnText"
            :collapse="triggerBtnCollapse"
            v-bind="{
              iconProps: {
                iconProps: {
                  icon: Settings
                },
              },
              ...triggerBtnProps,
            }"
          >
            <template v-if="slots['trigger-icon']" #btn-icon>
              <slot name="trigger-icon" />
            </template>
          </x-collapse-btn>
        </slot>
      </template>
      <template #default>
        <n-tabs>
          <n-tab-pane :name="colShowTabName">
            <n-list hoverable clickable>
              <n-list-item>
                <div class="x-crud-col-setting__columns-setting__all-reset">
                  <n-checkbox
                    size="small"
                    v-model:checked="isColumnsShowedAll"
                    :indeterminate="isColumnsShowedIndeterminate"
                    @update:checked="updateColumnsShowedAllHandler"
                  >
                    <span style="white-space: nowrap">{{ allBtnText }}</span>
                    <slot name="col-show-all-tip">
                      <x-question-tip
                        v-bind="{
                          tip: '被禁用是否选中展示的列不参与列全选的计算',
                          ...colShowAllTipProps,
                        }"
                      >
                        <template v-if="slots['col-show-all-tip-icon']" #trigger>
                          <slot name="col-show-all-tip-icon" />
                        </template>
                        <template v-if="slots['col-show-all-tip-content']" #tip>
                          <slot name="col-show-all-tip-content" />
                        </template>
                      </x-question-tip>
                    </slot>
                  </n-checkbox>
                  <n-button text size="small" @click="resetColumnsShowedHandler">{{ resetBtnText }}</n-button>
                </div>
              </n-list-item>
              <n-scrollbar
                class="x-crud-col-setting__columns-setting__list"
                :style="{maxHeight: SizeUtil.unitPreHandler(colSettingListMaxHeight)}"
                v-bind="{
                  trigger: 'none',
                  ...colSettingListScrollbarProps
                }"
              >
                <VueDraggable
                  v-model="columnsBackup"
                  handle=".x-crud-col-setting__columns-setting__item-handler"
                >
                  <div
                    v-for="column in columnsBackup"
                    :key="column.title"
                    class="x-crud-col-setting__columns-setting__item"
                  >
                    <n-list-item>
                      <div class="x-crud-col-setting__columns-setting__item-content">
                        <div
                          :class="
                              column.draggable ?
                                'x-crud-col-setting__columns-setting__item-handler' :
                                'x-crud-col-setting__columns-setting__item-handler--disabled'
                            "
                        >
                          <slot name="drag-icon">
                            <s-icon
                              v-bind="{
                                iconProps: {
                                  icon: ArrowsMoveVertical,
                                  width: 16,
                                  height: 16,
                                }
                              }"
                            />
                          </slot>
                        </div>
                        <div class="x-crud-col-setting__columns-setting__item-checkbox">
                          <n-checkbox size="small" :disabled="column.disableChecked" v-model:checked="column.checked">
                            <span style="white-space: nowrap">{{ column.title }}</span>
                          </n-checkbox>
                        </div>
                      </div>
                    </n-list-item>
                  </div>
                </VueDraggable>
              </n-scrollbar>
            </n-list>
          </n-tab-pane>
          <n-tab-pane :name="colFixTabName">
            <n-list hoverable clickable>
              <n-list-item>
                <div class="x-crud-col-setting__columns-setting__all-reset">
                  <n-checkbox
                    size="small"
                    :indeterminate="isColumnsFixedIndeterminate"
                    v-model:checked="isColumnsFixedAll"
                    @update:checked="updateColumnsFixedAllHandler"
                  >
                    <span style="white-space: nowrap">{{ allBtnText }}</span>
                    <slot name="col-fix-all-tip">
                      <x-question-tip
                        v-bind="{
                          tip: '没有配置列固定的列不参与列全选的计算',
                          ...colFixAllTipProps,
                        }"
                      >
                        <template v-if="slots['col-fix-all-tip-icon']" #trigger>
                          <slot name="col-fix-all-tip-icon" />
                        </template>
                        <template v-if="slots['col-fix-all-tip-content']" #tip>
                          <slot name="col-fix-all-tip-content" />
                        </template>
                      </x-question-tip>
                    </slot>
                  </n-checkbox>
                  <n-button text size="small" @click="resetColumnsFixedHandler">{{ resetBtnText }}</n-button>
                </div>
              </n-list-item>
              <n-scrollbar
                class="x-crud-col-setting__columns-setting__list"
                :style="{maxHeight: SizeUtil.unitPreHandler(colSettingListMaxHeight)}"
                v-bind="{
                  trigger: 'none',
                  ...colSettingListScrollbarProps
                }"
              >
                <div
                  v-for="column in columnsBackup"
                  :key="column.title"
                  class="x-crud-col-setting__columns-setting__item"
                >
                  <n-list-item>
                    <div class="x-crud-col-setting__columns-setting__item-content">
                      <div class="x-crud-col-setting__columns-setting__item-checkbox">
                        <n-checkbox
                          size="small"
                          :disabled="!(column.originFixed)"
                          v-model:checked="column.fixed"
                          :checked-value="column.originFixed"
                          :unchecked-value="false"
                        >
                          <span style="white-space: nowrap">{{ column.title }}</span>
                        </n-checkbox>
                      </div>
                    </div>
                  </n-list-item>
                </div>
              </n-scrollbar>
            </n-list>
          </n-tab-pane>
          <n-tab-pane :name="colAlignTabName">
            <n-list hoverable clickable>
              <n-list-item>
                <div
                  class="x-crud-col-setting__columns-setting__reset"
                  style="justify-content: flex-end"
                >
                  <n-button text size="small" @click="resetColumnsAlignHandler">{{ resetBtnText }}</n-button>
                </div>
              </n-list-item>
              <n-scrollbar
                class="x-crud-col-setting__columns-setting__list"
                :style="{maxHeight: SizeUtil.unitPreHandler(colSettingListMaxHeight)}"
                v-bind="{
                  trigger: 'none',
                  ...colSettingListScrollbarProps
                }"
              >
                <div
                  v-for="column in columnsBackup"
                  :key="column.title"
                  class="x-crud-col-setting__columns-setting__item"
                >
                  <n-list-item>
                    <div class="x-crud-col-setting__columns-setting__item-align">
                      <div class="x-crud-col-setting__columns-setting__item-align__title">
                        <span style="white-space: nowrap">{{ column.title }}</span>
                      </div>
                      <n-radio-group v-model:value="column.align" size="small">
                        <n-radio-button :value="'left'">{{ leftBtnText }}</n-radio-button>
                        <n-radio-button :value="'center'">{{ centerBtnText }}</n-radio-button>
                        <n-radio-button :value="'right'">{{ rightBtnText }}</n-radio-button>
                      </n-radio-group>
                    </div>
                  </n-list-item>
                </div>
              </n-scrollbar>
            </n-list>
          </n-tab-pane>
          <slot name="tab-pane-extra" :columns="columns" :columnsBackup="columnsBackup"></slot>
        </n-tabs>
      </template>
    </n-popover>
  </div>
</template>

<style lang="scss">
@use './style' as *;
</style>
